/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "StdAfx.h"
#include "BoundingSphere.h"
#include "IMesh.h"

namespace model {

BoundingSphere::BoundingSphere()
:	m_bIsNull(true), 
	m_vCenter(0,0,0), 
	m_fRadius(0)
{
}

BoundingSphere::BoundingSphere(const math::Vector3 &center, float radius)
:	m_bIsNull(false), 
	m_vCenter(center), 
	m_fRadius(radius)
{
}

BoundingSphere::~BoundingSphere(void)
{
}


const math::Vector3& BoundingSphere::getCenter() const
{
	return m_vCenter;
}

const float BoundingSphere::getRadius() const
{
	return m_fRadius;
}

void BoundingSphere::combine(const BoundingSphere &sphere)
{
	// Early exit if one of the bounding spheres is not defined
	if (m_fRadius == 0) {
		setSize(sphere.m_vCenter, sphere.m_fRadius);
		return;
	}
	else if (sphere.m_fRadius == 0)
		return;

	// Calculate the center difference
	math::Vector3 centerDiff = sphere.m_vCenter - m_vCenter; 
	// Calculate the radius difference
	float radiusDiff = sphere.m_fRadius - m_fRadius;
	// Square that
	float radiusDiffSqr = radiusDiff * radiusDiff;
	// Get the length squared
	float Lsqr = centerDiff.lengthSquared();

	if (radiusDiffSqr >= Lsqr ) 
	{
		if (radiusDiff >= 0.0) {
			setSize(sphere.m_vCenter, sphere.m_fRadius);
			return;
		}
		else
			return;
	}
	else
	{
		float L = sqrt( Lsqr );
		float t = (L+radiusDiff) / (2*L);
		// Create a new bounding sphere that encloses the two others
		setCenter( m_vCenter + t*centerDiff );
		setRadius((L+sphere.m_fRadius + m_fRadius)/2.0f);
	}
}

void BoundingSphere::setSize(const math::Vector3 &center, float radius)
{
	m_vCenter = center;
	m_fRadius = radius;
	m_bIsNull = false;
}

void BoundingSphere::setCenter(const math::Vector3 &center) 
{
	m_vCenter = center;
	m_bIsNull = false;
}

void BoundingSphere::setRadius(float radius)
{
	m_fRadius = radius;
	m_bIsNull = false;
}

const bool BoundingSphere::isNull() const
{
	return m_bIsNull;
}

bool BoundingSphere::isIntersecting(const BoundingSphere &other)
{
	return ( m_vCenter.distance(other.getCenter()) < m_fRadius + other.getRadius() );
}

} // end of Namespace
